package nsu.edu.zsq.service.impl.sys;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;

import nsu.edu.zsq.bean.ResitExam;
import nsu.edu.zsq.bean.ResitExamExample;
import nsu.edu.zsq.bean.ResitExamStudent;
import nsu.edu.zsq.bean.ResitExamStudentExample;
import nsu.edu.zsq.bean.ResitExamTeacher;
import nsu.edu.zsq.bean.ResitExamTeacherExample;
import nsu.edu.zsq.bean.SchRoomExample;
import nsu.edu.zsq.bean.StuScore;
import nsu.edu.zsq.bean.StuScoreExample;
import nsu.edu.zsq.bean.Student;
import nsu.edu.zsq.bean.StudentExample;
import nsu.edu.zsq.bean.Teacher;
import nsu.edu.zsq.common.RequestHolder;
import nsu.edu.zsq.dao.ResitExamMapper;
import nsu.edu.zsq.dao.ResitExamStudentMapper;
import nsu.edu.zsq.dao.ResitExamTeacherMapper;
import nsu.edu.zsq.dao.SchRoomMapper;
import nsu.edu.zsq.dao.StuScoreMapper;
import nsu.edu.zsq.dao.StudentMapper;
import nsu.edu.zsq.dao.TeacherMapper;
import nsu.edu.zsq.exception.ParamException;
import nsu.edu.zsq.param.PageQuery;
import nsu.edu.zsq.service.sys.ResitExamService;
import nsu.edu.zsq.service.sys.SysLogService;

/** 
* Description: 补考信息管理的service实现类<br>
*/
@Service
public class ResitExamServiceImpl implements ResitExamService {
    
    @Autowired
    private SysLogService sysLogService;
    @Autowired
    private StuScoreMapper stuScoreMapper;
    @Autowired
    private ResitExamMapper resitExamMapper;
    @Autowired
    private ResitExamStudentMapper resitExamStudentMapper;
    @Autowired
    private ResitExamTeacherMapper resitExamTeacherMapper;
    @Autowired
    private SchRoomMapper schRoomMapper;
    @Autowired
    private TeacherMapper teacherMapper;
    @Autowired
    private StudentMapper studentMapper;

    @Override
    public ResitExam getResitExam(int resitExamId) {
        ResitExam resitExam = resitExamMapper.selectByPrimaryKey(resitExamId);
        return resitExam;
    }

    @Override
    public PageInfo<ResitExam> listResitExamWithPage(PageQuery pageQuery) {
        PageHelper.startPage(pageQuery.getPageNum(),pageQuery.getPageSize());
        List<ResitExam> resitExams = resitExamMapper.listResitExam();
        PageInfo<ResitExam> pageInfo = new PageInfo<ResitExam>(resitExams, pageQuery.getNavigatePages());
        return pageInfo;
    }

    @Override
    public List<HashMap<String, String>> listStuScore() {
        List<HashMap<String, String>> listStuScore = stuScoreMapper.listStuScoreWithMajorNo();
        return listStuScore;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveCourseToResitExam(String[] courseNos, String[] majorNos) {
        List<ResitExam> after = new ArrayList<ResitExam>();
        for (int i = 0; i < courseNos.length; i++) {
            ResitExam afterResitExam = ResitExam.builder().courseNo(courseNos[i]).majorNo(majorNos[i])
                    .operator(RequestHolder.getCurrentSysUser().getAccount())
                    .operatorTime(new Date()).build();
            after.add(afterResitExam);
            // 检查添加的课程是否已经存在
            if (checkResitCourseExist(courseNos[i])) {
                throw new ParamException("该课程已经存在");
            }
            resitExamMapper.insertSelective(afterResitExam);
        }
        
        // 添加日志
        String instruction = "补考信息管理-添加补考课程";
        sysLogService.saveSysLogBySysUser(null, after, instruction);
    }

    /**
     * 检查添加的补考课程是否已经存在
     * @param courseNo 课程代码
     * @return boolean true：存在 false：不存在
     */
    private boolean checkResitCourseExist(String courseNo) {
        ResitExamExample example = new ResitExamExample();
        example.createCriteria().andCourseNoEqualTo(courseNo);
        return resitExamMapper.countByExample(example) > 0;
    }
    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteCourseFromResitExam(int[] resitExamIds) {
        List<ResitExam> before = new ArrayList<ResitExam>();
        for (int resitExamId : resitExamIds) {
            ResitExam beforeResitExam = getResitExam(resitExamId);
            before.add(beforeResitExam);
            // 1.删除补考课程
            resitExamMapper.deleteByPrimaryKey(resitExamId);
            // 2.删除监考教师信息
            ResitExamTeacherExample resitExamTeacherExample = new ResitExamTeacherExample();
            resitExamTeacherExample.createCriteria().andResitExamIdEqualTo(resitExamId);
            resitExamTeacherMapper.deleteByExample(resitExamTeacherExample);
            // 3.删除补考学生信息
            ResitExamStudentExample resitExamStudentExample = new ResitExamStudentExample();
            resitExamStudentExample.createCriteria().andResitExamIdEqualTo(resitExamId);
            resitExamStudentMapper.deleteByExample(resitExamStudentExample);
        }
        
        // 添加日志
        String instruction = "补考信息管理-删除";
        sysLogService.saveSysLogBySysUser(before, null, instruction);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateResitExam(ResitExam resitExam) {
        ResitExam beforeResitExam = getResitExam(resitExam.getId());
        ResitExam before = ResitExam.builder().id(beforeResitExam.getId()).examTime(beforeResitExam.getExamTime())
                .examDate(beforeResitExam.getExamDate()).operator(beforeResitExam.getOperator())
                .operatorTime(beforeResitExam.getOperatorTime()).build();
        resitExam.setOperator(RequestHolder.getCurrentSysUser().getAccount());
        resitExam.setOperatorTime(new Date());
        resitExamMapper.updateByPrimaryKeySelective(resitExam);
        
        // 添加日志
        String instruction = "补考信息管理-时间设置";
        sysLogService.saveSysLogBySysUser(before, resitExam, instruction);
    }

    @Override
    public Map<String, Object> getResitExamWithRoom(int resitExamId) {
        Map<String, Object> map = new HashMap<String, Object>(2);
        ResitExam resitExam = resitExamMapper.getResitExam(resitExamId);
        // 获取以;分隔的所有教室名称
        String allRoom = resitExam.getRoomName();
        String[] roomNames = null;
        if (allRoom != null && allRoom.length() > 0) {
            roomNames = allRoom.split(";");
        }
        map.put("resitExam", resitExam);
        map.put("roomNames", roomNames);
        return map;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveExamRoom(ResitExam resitExam) {
        // 1.检查教室是否存在
        if (!checkRoomNameExist(resitExam.getRoomName())) {
            throw new ParamException("该教室不存在，请重新输入");
        }
        ResitExam beforeResitExam = getResitExam(resitExam.getId());
        // 2.检查教室时间冲突
        if (checkExamTimeConflict(beforeResitExam, resitExam.getRoomName())) {
            throw new ParamException("教室考试时间安排冲突");
        }
        // 3.拼接考试教室
        StringBuilder sb = new StringBuilder();
        if (beforeResitExam.getRoomName() != null && beforeResitExam.getRoomName().length() > 0) {
            sb.append(beforeResitExam.getRoomName());
            sb.append(";");
        }
        sb.append(resitExam.getRoomName());
        resitExam.setRoomName(sb.toString());
        resitExam.setOperator(RequestHolder.getCurrentSysUser().getAccount());
        resitExam.setOperatorTime(new Date());
        ResitExam before = ResitExam.builder().id(beforeResitExam.getId()).roomName(beforeResitExam.getRoomName())
                .operator(beforeResitExam.getOperator()).operatorTime(beforeResitExam.getOperatorTime()).build();
        resitExamMapper.updateByPrimaryKeySelective(resitExam);
        
        // 添加日志
        String instruction = "补考信息管理-考试安排-添加考试教室";
        sysLogService.saveSysLogBySysUser(before, resitExam, instruction);
    }

    /**
     * 检查教室是否存在
     * @param roomName 教室名称
     * @return boolean true：存在 false：不存在
     */
    private boolean checkRoomNameExist(String roomName) {
        SchRoomExample example = new SchRoomExample();
        example.createCriteria().andRoomNameEqualTo(roomName);
        return schRoomMapper.countByExample(example) > 0;
    }
    
    /**
     * 检查是否教室考试时间冲突
     * @param resitExam 补考课程信息
     * @param roomName 考试教室
     * @return boolean true：冲突 false：不冲突
     */
    private boolean checkExamTimeConflict(ResitExam resitExam, String roomName) {
        ResitExamExample example = new ResitExamExample();
        example.createCriteria().andExamDateEqualTo(resitExam.getExamDate())
            .andExamTimeEqualTo(resitExam.getExamTime());
        List<ResitExam> listResitExam = resitExamMapper.selectByExample(example);
        for (ResitExam resitExam2 : listResitExam) {
            String allRoom = resitExam2.getRoomName();
            String[] roomNames = new String[] {};
            if (allRoom != null && allRoom.length() > 0) {
                roomNames = allRoom.split(";");
            }
            for (String string : roomNames) {
                if (string.equals(roomName)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delExamRoom(int resitExamId, String[] roomNames) {
        ResitExam beforeResitExam = getResitExam(resitExamId);
        ResitExam before = ResitExam.builder().id(beforeResitExam.getId()).roomName(beforeResitExam.getRoomName())
                .operator(beforeResitExam.getOperator()).operatorTime(beforeResitExam.getOperatorTime()).build();
        // 拼接新的考试教室
        StringBuilder sb = new StringBuilder();
        if (beforeResitExam.getRoomName() != null && beforeResitExam.getRoomName().length() > 0) {
            String[] beforeRoomNames = beforeResitExam.getRoomName().split(";");
            for (String beforeRoomName : beforeRoomNames) {
                boolean flag = true;
                for (String roomName : roomNames) {
                    if (beforeRoomName.equals(roomName)) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    sb.append(beforeRoomName);
                    sb.append(";");
                }
            }
        } else {
            return;
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        ResitExam after = ResitExam.builder().id(beforeResitExam.getId()).roomName(sb.toString())
                .operator(RequestHolder.getCurrentSysUser().getAccount())
                .operatorTime(new Date()).build();
        // 删除考试教室
        resitExamMapper.updateByPrimaryKeySelective(after);
        List<String> listRoomName = new ArrayList<String>();
        for (String roomName : roomNames) {
            listRoomName.add(roomName);
        }
        // 删除监考教师信息
        ResitExamTeacherExample resitExamTeacherExample = new ResitExamTeacherExample();
        resitExamTeacherExample.createCriteria().andResitExamIdEqualTo(resitExamId).andRoomNameIn(listRoomName);
        resitExamTeacherMapper.deleteByExample(resitExamTeacherExample);
        // 删除补考学生信息
        ResitExamStudentExample resitExamStudentExample = new ResitExamStudentExample();
        resitExamStudentExample.createCriteria().andResitExamIdEqualTo(resitExamId).andRoomNameIn(listRoomName);
        resitExamStudentMapper.deleteByExample(resitExamStudentExample);
        
        
        // 添加日志
        String instruction = "补考信息管理-考试安排-删除考试教室";
        sysLogService.saveSysLogBySysUser(before, after, instruction);
    }

    @Override
    public List<ResitExamTeacher> listResitExamTeacher(ResitExamTeacher resitExamTeacher) {
        List<ResitExamTeacher> listResitExamTeacher = resitExamTeacherMapper.listResitExamTeacher(resitExamTeacher);
        return listResitExamTeacher;
    }

    @Override
    public PageInfo<Teacher> listTeacherByMajorNoWithPage(String majorNo, PageQuery pageQuery) {
        PageHelper.startPage(pageQuery.getPageNum(),pageQuery.getPageSize());
        List<Teacher> listTeacher = teacherMapper.listTeacherByMajorNo(majorNo);
        PageInfo<Teacher> pageInfo = new PageInfo<Teacher>(listTeacher, pageQuery.getNavigatePages());
        return pageInfo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveTeacherToResitExam(ResitExamTeacher resitExamTeacher, String[] teacherNos) {
        List<ResitExamTeacher> after = new ArrayList<ResitExamTeacher>();
        ResitExam resitExam = getResitExam(resitExamTeacher.getResitExamId());
        resitExamTeacher.setExamDate(resitExam.getExamDate());
        resitExamTeacher.setExamTime(resitExam.getExamTime());
        resitExamTeacher.setCourseNo(resitExam.getCourseNo());
        for (String teacherNo : teacherNos) {
            resitExamTeacher.setTeacherNo(teacherNo);
            after.add(resitExamTeacher);
            // 检查该教师是否已经存在
            if (checkExamTeacherExist(resitExamTeacher)) {
                throw new ParamException("该监考教师已经存在");
            }
            resitExamTeacherMapper.insertSelective(resitExamTeacher);
        }
        
        // 添加日志
        String instruction = "补考信息管理-添加监考教师";
        sysLogService.saveSysLogBySysUser(null, after, instruction);

    }

    /**
     * 检查在一个考试课程中是否已经存在该监考教师
     * @param resitExamTeacher 监考教师信息
     * @return boolean true：存在 false：不存在
     */
    private boolean checkExamTeacherExist(ResitExamTeacher resitExamTeacher) {
        ResitExamTeacherExample example = new ResitExamTeacherExample();
        example.createCriteria().andResitExamIdEqualTo(resitExamTeacher.getResitExamId()).andTeacherNoEqualTo(resitExamTeacher.getTeacherNo());
        return resitExamTeacherMapper.countByExample(example) > 0;
    }
    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delResitExamTeacher(int[] resitExamTeacherIds) {
        List<ResitExamTeacher> before = new ArrayList<ResitExamTeacher>();
        for (int resitExamTeacherId : resitExamTeacherIds) {
            ResitExamTeacher beforeResitExamTeacher = resitExamTeacherMapper.selectByPrimaryKey(resitExamTeacherId);
            before.add(beforeResitExamTeacher);
            resitExamTeacherMapper.deleteByPrimaryKey(resitExamTeacherId);
        }

        // 添加日志
        String instruction = "补考信息管理-删除监考教师";
        sysLogService.saveSysLogBySysUser(before, null, instruction);
    }

    @Override
    public List<ResitExamStudent> listResitExamStudent(ResitExamStudent resitExamStudent) {
        List<ResitExamStudent> listResitExamStudent = resitExamStudentMapper.listResitExamStudent(resitExamStudent);
        return listResitExamStudent;
    }

    @Override
    public PageInfo<Student> listStudentByCourseNoWithPage(String courseNo, PageQuery pageQuery) {
        // 1.首先获取该课程下需要补考的学生
        StuScoreExample stuScoreExample = new StuScoreExample();
        stuScoreExample.createCriteria().andCourseNoEqualTo(courseNo).andResitStatusEqualTo(1);
        List<StuScore> listStuScore = stuScoreMapper.selectByExample(stuScoreExample);
        // 2.获取补考课程中已经存在的考试学生
        ResitExamStudentExample resitExamStudentExample = new ResitExamStudentExample();
        resitExamStudentExample.createCriteria().andCourseNoEqualTo(courseNo);
        List<ResitExamStudent> listResitExamStudent = resitExamStudentMapper.selectByExample(resitExamStudentExample);
        // 需要查找的学号
        List<String> stuNo = new ArrayList<String>();
        for (StuScore stuScore : listStuScore) {
            boolean flag = true;
            for (ResitExamStudent resitExamStudent : listResitExamStudent) {
                if (stuScore.getStuNo().equals(resitExamStudent.getStuNo())) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                stuNo.add(stuScore.getStuNo());
            }
        }
        // 3.获取这些学生的信息
        PageHelper.startPage(pageQuery.getPageNum(),pageQuery.getPageSize());
        if (stuNo.size() <= 0) {
            PageInfo<Student> pageInfo = new PageInfo<Student>(new ArrayList<Student>(), pageQuery.getNavigatePages());
            return pageInfo;
        }
        StudentExample studentExample = new StudentExample();
        // 如果这里的stuNo为空，则sql会报错
        studentExample.createCriteria().andStuNoIn(stuNo);
        List<Student> listStudent = studentMapper.selectByExample(studentExample);
        PageInfo<Student> pageInfo = new PageInfo<Student>(listStudent, pageQuery.getNavigatePages());
        return pageInfo;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveStudentToResitExam(ResitExamStudent resitExamStudent, String[] stuNos) {
        List<ResitExamStudent> after = new ArrayList<ResitExamStudent>();
        ResitExam resitExam = getResitExam(resitExamStudent.getResitExamId());
        resitExamStudent.setExamDate(resitExam.getExamDate());
        resitExamStudent.setExamTime(resitExam.getExamTime());
        resitExamStudent.setCourseNo(resitExam.getCourseNo());
        for (String stuNo : stuNos) {
            resitExamStudent.setStuNo(stuNo);
            after.add(resitExamStudent);
            // 检查该学生是否已经存在
            if (checkExamStudentExist(resitExamStudent)) {
                throw new ParamException("考场已经存在该学生");
            }
            resitExamStudentMapper.insertSelective(resitExamStudent);
        }
        
        // 添加日志
        String instruction = "补考信息管理-添加考试学生";
        sysLogService.saveSysLogBySysUser(null, after, instruction);

    }

    /**
     * 检查考试课程中是否已经存在该考生
     * @param resitExamStudent 考试学生信息
     * @return boolean true：存在 false：不存在
     */
    private boolean checkExamStudentExist(ResitExamStudent resitExamStudent) {
        ResitExamStudentExample example = new ResitExamStudentExample();
        example.createCriteria().andResitExamIdEqualTo(resitExamStudent.getResitExamId()).andStuNoEqualTo(resitExamStudent.getStuNo());
        return resitExamStudentMapper.countByExample(example) > 0;
    }
    
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delResitExamStudent(int[] resitExamStudentIds) {
        List<ResitExamStudent> before = new ArrayList<ResitExamStudent>();
        for (int resitExamStudentId : resitExamStudentIds) {
            ResitExamStudent beforeResitExamStudent = resitExamStudentMapper.selectByPrimaryKey(resitExamStudentId);
            before.add(beforeResitExamStudent);
            resitExamStudentMapper.deleteByPrimaryKey(resitExamStudentId);
        }
        
        // 添加日志
        String instruction = "补考信息管理-删除考试学生";
        sysLogService.saveSysLogBySysUser(before, null, instruction);

    }

    @Override
    public void autoSeatNumber(ResitExamStudent resitExamStudent) {
        ResitExamStudentExample resitExamStudentExample = new ResitExamStudentExample();
        resitExamStudentExample.createCriteria().andResitExamIdEqualTo(resitExamStudent.getResitExamId()).andRoomNameEqualTo(resitExamStudent.getRoomName());
        resitExamStudentExample.setOrderByClause("stu_no asc");
        List<ResitExamStudent> listResitExamStudent = resitExamStudentMapper.selectByExample(resitExamStudentExample);
        List<ResitExamStudent> before = new ArrayList<ResitExamStudent>();
        List<ResitExamStudent> after = new ArrayList<ResitExamStudent>();
        for (int i = 0; i < listResitExamStudent.size(); i++) {
            ResitExamStudent oldResitExamStudent = listResitExamStudent.get(i);
            ResitExamStudent beforeResitExamStudent = ResitExamStudent.builder().id(oldResitExamStudent.getId())
                    .stuNo(oldResitExamStudent.getStuNo()).seatNumber(oldResitExamStudent.getSeatNumber()).build();
            before.add(beforeResitExamStudent);
            ResitExamStudent afterResitExamStudent = ResitExamStudent.builder().id(oldResitExamStudent.getId())
                    .stuNo(oldResitExamStudent.getStuNo()).seatNumber(i + 1).build();
            after.add(afterResitExamStudent);
            resitExamStudentMapper.updateByPrimaryKeySelective(afterResitExamStudent);
        }
        
        // 添加日志
        String instruction = "补考信息管理-自动排号";
        sysLogService.saveSysLogBySysUser(before, after, instruction);
    }

}
